#include <SDL.h>
#include <stdio.h>
#include "init.h"
#include "main.h"
#include "keypress.h"
#include "texture.h"
#include <SDL_image.h>
#include "colorkey.h"
#include <SDL_ttf.h>
#include <SDL_mixer.h>
#include "render.h"
#include "motion.h"
#include "texture.h"
#include "multiwin.h"

#define IMAGE_PATH "F:/coding2/C-practice/sdl2/sdl2qt/img/"
#define FONT_PATH "F:/coding2/C-practice/sdl2/sdl2qt/font/"
#define MIX_PATH "F:/coding2/codeblocks_projects/21_sound_effects_and_music/21_sound_effects_and_music/"
#define FILE_PATH "F:/coding2/C-practice/sdl2/sdl2qt/file/"

#define FRAMES 4

//#define KEYPRESS
//#define TEXTURE
//#define GEOMETRY_RENDER
//#define VIEWPORT
//#define COLORKEY
//#define CLIP_RENDER
//#define COLOR_MODULATION
//#define ALPHA_BLENDING
//#define ANIMATED_SPRITES //Animated Sprites and VSync
//#define ROTATION_FLIPPING //Rotation and Flipping
//#define TURE_TYPE_FONT //True Type Fonts
//#define MOUSE_EVENTS //Mouse Events
//#define KEY_STATES //Key States
//#define SOUND_MUSIC //Sound Effects and Music
//#define TIMING //Timing
//#define ADVANCED_TIMER //Advanced Timers and Calculating Frame Rate
//#define MOTION //motion and Collision Detection
//#define PRE_PIXEL_COLLISION_DEC //Per-pixel Collision Detection
//#define CIRCLE_COLLISION_DEC //Circular Collision Detection
//#define SCROLLING //Scrolling
//#define SCROLLING_BACKGROUNDS //Scrolling Backgrounds
//#define TEXT_INPUT_AND_CLIPBOARD //Text Input And Clipboard Handling
//#define FILE_READ_WRITE //File Reading and Writing
//#define WIN_EVENTS //Window Events
//#define MULTIPLE_WINS //Multiple Windows
//#define PARTICLE_ENGINES //Particle Engines
#define TEXTURE_MAN //Texture Manipulation

int main( int argc, char* args[] ){
    UNUSED(argc);
    UNUSED(args);

#ifdef TEXTURE_MAN
    SDL_Window *tmWin = NULL;
    SDL_Renderer *tmRenderer = NULL;
    SDL_Color backgroundColor = {0xff,0xff,0xff,0xff};

    if(!initWindowAndRenderer(&tmWin, &tmRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    Texture imgTexure = loadImageTextureWithFormat(&tmWin, &tmRenderer, IMAGE_PATH"person.png");

    SDL_LockTexture( imgTexure.texture, NULL, &imgTexure.pixels, &imgTexure.pitch );
    //Allocate format from window
    Uint32 format = SDL_GetWindowPixelFormat( tmWin );
    SDL_PixelFormat* mappingFormat = SDL_AllocFormat( format );

    //Get pixel data
    Uint32* pixels = (Uint32*)imgTexure.pixels;
    int pixelCount = ( imgTexure.pitch / 4 ) * imgTexure.h;
    printf("imgTexure.w=%d, imgTexure.h=%d, imgTexure.pitch=%d\n", imgTexure.w, imgTexure.h, imgTexure.pitch);

    //Map colors
    Uint32 colorKey = SDL_MapRGB( mappingFormat, 0, 0xFF, 0xFF );
    Uint32 transparent = SDL_MapRGBA( mappingFormat, 0xFF, 0xFF, 0xFF, 0x00 );

    //Color key pixels
    for( int i = 0; i < pixelCount; ++i ){
        if( pixels[ i ] == colorKey ){
            pixels[ i ] = transparent;
        }
    }
    SDL_UnlockTexture(imgTexure.texture);    //Free format
    SDL_FreeFormat( mappingFormat );

    bool quit = false;
    SDL_Event e;
    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }
        }
        renderClearEx(&tmRenderer, &backgroundColor);
        SDL_SetRenderDrawColor(tmRenderer, 0, 0, 0, 0xFF );

        renderImage(&tmRenderer, &imgTexure, NULL, (WINDOW_WIDTH-imgTexure.w)/2, (WINDOW_HEIGHT-imgTexure.h)/2);

        SDL_RenderPresent(tmRenderer);
    }

    SDL_DestroyWindow(tmWin);
    SDL_DestroyRenderer(tmRenderer);
    IMG_Quit();
    SDL_Quit();
    printf("SDL Quit!\n");
#endif

#ifdef PARTICLE_ENGINES
    SDL_Window *peWin = NULL;
    SDL_Renderer *peRenderer = NULL;
    SDL_Color backgroundColor = {0xff,0xff,0xff,0xff};

    if(!initWindowAndRenderer(&peWin, &peRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};
    Texture dotImg = loadImageTexture(&peRenderer, IMAGE_PATH"dot.png");
    Texture redImg = loadImageTexture(&peRenderer, IMAGE_PATH"red.png");
    Texture greenImg = loadImageTexture(&peRenderer, IMAGE_PATH"green.png");
    Texture blueImg = loadImageTexture(&peRenderer, IMAGE_PATH"blue.png");
    Texture shimmerImg = loadImageTexture(&peRenderer, IMAGE_PATH"shimmer.png");
    Texture colorImgs[3] = {redImg, greenImg, blueImg};
    Particles pcls[10];
    Dot dot;
    initDot(&dot, &dotImg);
    initParticals(&dot, pcls, 10, colorImgs, 3);

    SDL_Rect wallRect = {200, 60, 20, 260};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else{
                dotHandle(&dot, &e);
            }
        }
        dotMove(&dot, &wallRect);

        renderClearEx(&peRenderer, &backgroundColor);
        SDL_SetRenderDrawColor(peRenderer, 0, 0, 0, 0xFF );
        SDL_RenderDrawRect(peRenderer, &wallRect);
        renderText(&peRenderer, &dot.texture, font, &fontColor, "M o t i o n", WINDOW_WIDTH/2, WINDOW_HEIGHT/2);

        renderParticals(&peRenderer, &dot, pcls, 10, colorImgs, 3, shimmerImg);
        renderImage(&peRenderer, &dotImg, NULL, dot.motion.posX, dot.motion.posY);
        SDL_RenderPresent(peRenderer);
    }

    freeDot(&dot);
    SDL_DestroyWindow(peWin);
    SDL_DestroyRenderer(peRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("SDL Quit!\n");
#endif

#ifdef MULTIPLE_WINS

#define TOTAL_WINS 3

    SdlWindow wins[TOTAL_WINS];

    if(initWins(wins, TOTAL_WINS) < 0){
        return -1;
    }

    printf("Display Numbers : %d\n", SDL_GetNumVideoDisplays());

    SDL_Color backgroundColor = {192,192,192,0xff};

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else if(e.type == SDL_WINDOWEVENT) {
                winsEventsHandle(wins, TOTAL_WINS, &e);
                for(int i = 0; i < TOTAL_WINS; i++){
                    if(wins[i].bClose == false){
                        quit = false;
                        break;
                    }else{
                        quit = true;
                    }
                }
            }else if(e.type == SDL_KEYDOWN){
                switch (e.key.keysym.sym) {
                case SDLK_1:
                    if(!wins[0].bClose){
                        SDL_ShowWindow(wins[0].win);
                        SDL_RaiseWindow(wins[0].win);
                    }else{
                        printf("this window is closed!\n");
                    }
                    break;
                case SDLK_2:
                    if(!wins[1].bClose){
                        SDL_ShowWindow(wins[1].win);
                        SDL_RaiseWindow(wins[1].win);
                    }else{
                        printf("this window is closed!\n");
                    }
                    break;
                case SDLK_3:
                    if(!wins[2].bClose){
                        SDL_ShowWindow(wins[2].win);
                        SDL_RaiseWindow(wins[2].win);
                    }else{
                        printf("this window is closed!\n");
                    }
                    break;
                }
            }
        }

        for(int i = 0; i < TOTAL_WINS; i++){
            renderClearEx(&wins[i].render, &backgroundColor);
            renderText(&wins[i].render, &wins[i].texture, font, &fontColor, "Window Events", wins[i].width/2, wins[i].height/2);
            SDL_RenderPresent(wins[i].render);
        }

    }

    for(int i = 0; i < TOTAL_WINS; i++){
        SDL_DestroyWindow(wins[i].win);
        SDL_DestroyRenderer(wins[i].render);
    }
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef WIN_EVENTS
    SDL_Window *weWin = NULL;
    SDL_Renderer *weRenderer = NULL;
    SDL_Texture *weTexture = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};
    int winWidth = WINDOW_WIDTH;
    int winHeight = WINDOW_HEIGHT;

    if(!initWindowAndRenderer(&weWin, &weRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }
    SDL_SetWindowResizable(weWin, SDL_TRUE);

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else if(e.type == SDL_WINDOWEVENT){
                switch (e.window.event) {
                case SDL_WINDOWEVENT_SIZE_CHANGED:
                    winWidth = e.window.data1;
                    winHeight = e.window.data2;
                    break;
                case SDL_WINDOWEVENT_EXPOSED:
                    printf("repaint on exposure.\n");
                    break;
                case SDL_WINDOWEVENT_ENTER:
                    printf("mouse entered window.\n");
                    break;
                case SDL_WINDOWEVENT_LEAVE:
                    printf("mouse leave window.\n");
                    break;
                case SDL_WINDOWEVENT_FOCUS_GAINED:
                    printf("window has keyboard focus.\n");
                    break;
                case SDL_WINDOWEVENT_FOCUS_LOST:
                    printf("window lost keyboard focus.\n");
                    break;
                case SDL_WINDOWEVENT_MAXIMIZED:
                    printf("window minimized.\n");
                    break;
                case SDL_WINDOWEVENT_MINIMIZED:
                    printf("window maximized.\n");
                    break;
                case SDL_WINDOWEVENT_RESTORED:
                    printf("window restored.\n");
                    break;
                }
            }

        }
        renderClearEx(&weRenderer, &backgroundColor);

        renderText(&weRenderer, &weTexture, font, &fontColor, "Window Events", winWidth/2, winHeight/2);

        SDL_RenderPresent(weRenderer);
    }

    SDL_DestroyWindow(weWin);
    SDL_DestroyRenderer(weRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef FILE_READ_WRITE
#define TOTAL_DATA 10
    SDL_Window *frwWin = NULL;
    SDL_Renderer *frwRenderer = NULL;
    SDL_Texture *frwTexture = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};
    Sint32 gData[TOTAL_DATA];

    if(!initWindowAndRenderer(&frwWin, &frwRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    SDL_RWops *file = SDL_RWFromFile(FILE_PATH"nums.bin", "r+b");
    if(!file){
        printf("Warning: Unable to open file, SDL_ERROR: %s\n", SDL_GetError());
        //create file
        file = SDL_RWFromFile(FILE_PATH"nums.bin", "w+b");
        if(!file){
            printf("Error: Unable to create file, SDL_ERROR: %s\n", SDL_GetError());
            return -3;
        }else{
            printf("Create a new file! \n");
            //init data
            for(int i = 0; i < TOTAL_DATA; i++){
                gData[i] = i;
                SDL_RWwrite(file, &gData[i], sizeof (Sint32), 1);
            }
            SDL_RWclose(file);
        }
    }else{
        printf("Open file OK!\n");
        //read file
        printf("Reading: \n");
        for(int i = 0; i < TOTAL_DATA; i++){
            SDL_RWread(file, &gData[i], sizeof (Sint32), 1);
            printf("read: %d\n", gData[i]);
        }
        SDL_RWclose(file);
    }

    char *str = malloc(1024);
    SDL_memset(str, '\0', 1024);
    while (!quit) {
        bool bRenderText = false;
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else if(e.type == SDL_KEYDOWN){
                if(e.key.keysym.sym == SDLK_BACKSPACE && SDL_strlen(str) > 0){
                    str[SDL_strlen(str) - 1] = '\0';
                    bRenderText = true;
                }else if(e.key.keysym.sym == SDLK_c && (SDL_GetModState() & KMOD_CTRL)){
                    SDL_SetClipboardText(str);
                }else if(e.key.keysym.sym == SDLK_v && (SDL_GetModState() & KMOD_CTRL)){
                    str = SDL_GetClipboardText();
                    bRenderText = true;
                }
            }else if(e.type == SDL_TEXTINPUT){
                //Not copy or pasting
                if( !( SDL_GetModState() & KMOD_CTRL &&
                       ( e.text.text[0] == 'c' || e.text.text[0] == 'C' || e.text.text[0] == 'v' || e.text.text[0] == 'V' )
                     ) ){
                    //Append character
                    printf("text = %s\n", e.text.text);
                    SDL_strlcpy(str + SDL_strlen(str), e.text.text, SDL_strlen(e.text.text) + 1);
                    printf("after append str = %s\n", str);
                    bRenderText = true;
                }
            }
        }
        renderClearEx(&frwRenderer, &backgroundColor);
        if(bRenderText){
            if(SDL_strlen(str) > 0){
                printf("str = %s\n", str);
            }
        }
        if(SDL_strlen(str) > 0) renderText(&frwRenderer, &frwTexture, font, &fontColor, str, WINDOW_WIDTH /2 - 100, 150);
        renderText(&frwRenderer, &frwTexture, font, &fontColor, "Input text: ", WINDOW_WIDTH /2 - 100, 50);

        SDL_RenderPresent(frwRenderer);
    }

    free(str);
    SDL_DestroyWindow(frwWin);
    SDL_DestroyRenderer(frwRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef TEXT_INPUT_AND_CLIPBOARD
    SDL_Window *tcWin = NULL;
    SDL_Renderer *tcRenderer = NULL;
    SDL_Texture *tcTexture = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};

    if(!initWindowAndRenderer(&tcWin, &tcRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    char *str = malloc(1024);
    SDL_memset(str, '\0', 1024);
    while (!quit) {
        bool bRenderText = false;
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else if(e.type == SDL_KEYDOWN){
                if(e.key.keysym.sym == SDLK_BACKSPACE && SDL_strlen(str) > 0){
                    str[SDL_strlen(str) - 1] = '\0';
                    bRenderText = true;
                }else if(e.key.keysym.sym == SDLK_c && (SDL_GetModState() & KMOD_CTRL)){
                    SDL_SetClipboardText(str);
                }else if(e.key.keysym.sym == SDLK_v && (SDL_GetModState() & KMOD_CTRL)){
                    str = SDL_GetClipboardText();
                    bRenderText = true;
                }
            }else if(e.type == SDL_TEXTINPUT){
                //Not copy or pasting
                if( !( SDL_GetModState() & KMOD_CTRL &&
                       ( e.text.text[0] == 'c' || e.text.text[0] == 'C' || e.text.text[0] == 'v' || e.text.text[0] == 'V' )
                     ) ){
                    //Append character
                    printf("text = %s\n", e.text.text);
                    SDL_strlcpy(str + SDL_strlen(str), e.text.text, SDL_strlen(e.text.text) + 1);
                    printf("after append str = %s\n", str);
                    bRenderText = true;
                }
            }            
        }
        renderClearEx(&tcRenderer, &backgroundColor);
        if(bRenderText){
            if(SDL_strlen(str) > 0){
                printf("str = %s\n", str);
            }
        }
        if(SDL_strlen(str) > 0) renderText(&tcRenderer, &tcTexture, font, &fontColor, str, WINDOW_WIDTH /2 - 100, 150);
        renderText(&tcRenderer, &tcTexture, font, &fontColor, "Input text: ", WINDOW_WIDTH /2 - 100, 50);

        SDL_RenderPresent(tcRenderer);
    }

    free(str);
    SDL_DestroyWindow(tcWin);
    SDL_DestroyRenderer(tcRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef SCROLLING_BACKGROUNDS
    SDL_Window *sbWin = NULL;
    SDL_Renderer *sbRenderer = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};

    if(!initWindowAndRenderer(&sbWin, &sbRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};
    Texture dotImg = loadImageTexture(&sbRenderer, IMAGE_PATH"dot.png");
    Texture bgImg = loadImageTexture(&sbRenderer, IMAGE_PATH"background2.png");
    printf("bgImg.w=%d, bgImg.h=%d\n", bgImg.w, bgImg.h);
    Dot dot;
    initDot(&dot, &dotImg);
    SDL_Rect screenEdgeRect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    int bgScrollingOffset = 0;

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else{
                dotHandle(&dot, &e);
            }
        }
        dotMoveScroll(&dot, &screenEdgeRect);

        bgScrollingOffset--;
        if(bgScrollingOffset < -bgImg.w){
            bgScrollingOffset = 0;
        }

        renderClearEx(&sbRenderer, &backgroundColor);

        renderImage(&sbRenderer, &bgImg, NULL, bgScrollingOffset, 0); //render current background
        renderImage(&sbRenderer, &bgImg, NULL, bgScrollingOffset + bgImg.w, 0); //render next background
        renderText(&sbRenderer, &dot.texture, font, &fontColor, "Scrolling Background", WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
        renderImage(&sbRenderer, &dotImg, NULL, dot.motion.posX, dot.motion.posY);

        SDL_RenderPresent(sbRenderer);
    }

    freeDot(&dot);
    SDL_DestroyWindow(sbWin);
    SDL_DestroyRenderer(sbRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef SCROLLING
    SDL_Window *scWin = NULL;
    SDL_Renderer *scRenderer = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};

    if(!initWindowAndRenderer(&scWin, &scRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};
    Texture dotImg = loadImageTexture(&scRenderer, IMAGE_PATH"dot.png");
    Texture bgImg = loadImageTexture(&scRenderer, IMAGE_PATH"background2.png");
    printf("bgImg.w=%d, bgImg.h=%d\n", bgImg.w, bgImg.h);
    Dot dot;
    initDot(&dot, &dotImg);
    SDL_Rect cameraRect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
    SDL_Rect bgEdgeRect = {0, 0, bgImg.w, bgImg.h};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else{
                dotHandle(&dot, &e);
            }
        }
        dotMoveScroll(&dot, &bgEdgeRect);

        cameraRect.x = dot.motion.posX + dot.w/2 - WINDOW_WIDTH/2;
        cameraRect.y = dot.motion.posY + dot.h/2 - WINDOW_HEIGHT/2;

        if(cameraRect.x < 0){
            cameraRect.x = 0;
        }else if(cameraRect.x > bgImg.w - cameraRect.w){
            cameraRect.x = bgImg.w - cameraRect.w;
        }

        if(cameraRect.y < 0){
            cameraRect.y = 0;
        }else if(cameraRect.y > bgImg.h - cameraRect.h){
            cameraRect.y = bgImg.h - cameraRect.h;
        }

        renderClearEx(&scRenderer, &backgroundColor);

        renderImage(&scRenderer, &bgImg, &cameraRect, 0, 0);
        renderText(&scRenderer, &dot.texture, font, &fontColor, "M o t i o n", WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
        renderImage(&scRenderer, &dotImg, NULL, dot.motion.posX - cameraRect.x, dot.motion.posY - cameraRect.y);

        SDL_RenderPresent(scRenderer);
    }

    freeDot(&dot);
    SDL_DestroyWindow(scWin);
    SDL_DestroyRenderer(scRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");

#endif

#ifdef CIRCLE_COLLISION_DEC
    SDL_Window *ccWin = NULL;
    SDL_Renderer *ccRenderer = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};

    if(!initWindowAndRenderer(&ccWin, &ccRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};
    Texture dotImg = loadImageTexture(&ccRenderer, IMAGE_PATH"dot.png");
    Texture otherDotImg = loadImageTexture(&ccRenderer, IMAGE_PATH"circle.png");
    Dot dot, otherDot;
    initDotWithPos(&dot, &dotImg, 0, 0);
    initDotWithPos(&otherDot, &otherDotImg, 100, 200);
    SDL_Rect wallRect = {200, 60, 20, 260};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else{
                dotHandle(&dot, &e);
            }
        }
        dotMoveWithCircleAndRect(&dot, &otherDot, &wallRect);

        renderClearEx(&ccRenderer, &backgroundColor);
        SDL_SetRenderDrawColor(ccRenderer, 0xff, 0xff, 0xff, 0xFF );
        SDL_RenderDrawRect(ccRenderer, &wallRect);
        renderText(&ccRenderer, &dot.texture, font, &fontColor, "Circle and Rect", WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
        renderImage(&ccRenderer, &dotImg, NULL, dot.motion.posX, dot.motion.posY);
        renderImage(&ccRenderer, &otherDotImg, NULL, otherDot.motion.posX, otherDot.motion.posY);
        SDL_RenderPresent(ccRenderer);
    }

    freeDot(&dot);
    freeDot(&otherDot);
    SDL_DestroyWindow(ccWin);
    SDL_DestroyRenderer(ccRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef PRE_PIXEL_COLLISION_DEC
    SDL_Window *pcWin = NULL;
    SDL_Renderer *pcRenderer = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};

    if(!initWindowAndRenderer(&pcWin, &pcRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};
    Texture dotImg = loadImageTexture(&pcRenderer, IMAGE_PATH"dot.png");
    Texture otherDotImg = loadImageTexture(&pcRenderer, IMAGE_PATH"dot.png");
    Dot dot, otherDot;
    initDotWithPos(&dot, &dotImg, 0, 0);
    initDotWithPos(&otherDot, &otherDotImg, 100, 200);

    printf("cNum1=%d, cNum2=%d\n", dot.collidersNum, otherDot.collidersNum);
    SDL_Rect wallRect = {200, 60, 20, 260};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else{
                dotHandle(&dot, &e);
            }
        }
        dotMoveEx(&dot, &otherDot);

        renderClearEx(&pcRenderer, &backgroundColor);
        SDL_SetRenderDrawColor(pcRenderer, 0xff, 0xff, 0xff, 0xFF );
        SDL_RenderDrawRect(pcRenderer, &wallRect);
        renderText(&pcRenderer, &dot.texture, font, &fontColor, "M o t i o n", WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
        renderImage(&pcRenderer, &dotImg, NULL, dot.motion.posX, dot.motion.posY);
        renderImage(&pcRenderer, &otherDotImg, NULL, otherDot.motion.posX, otherDot.motion.posY);
        SDL_RenderPresent(pcRenderer);
    }

    freeDot(&dot);
    SDL_DestroyWindow(pcWin);
    SDL_DestroyRenderer(pcRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");

#endif
#ifdef MOTION
    SDL_Window *mWin = NULL;
    SDL_Renderer *mRenderer = NULL;
    SDL_Color backgroundColor = {192,192,192,0xff};

    if(!initWindowAndRenderer(&mWin, &mRenderer)){
        printf("Create window and render failed!\n");
        return -1;
    }

    bool quit = false;
    SDL_Event e;
    TTF_Font *font = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
    SDL_Color fontColor = {245,245,245,0xff};
    Texture dotImg = loadImageTexture(&mRenderer, IMAGE_PATH"dot.png");
    Dot dot;
    initDot(&dot, &dotImg);
    SDL_Rect wallRect = {200, 60, 20, 260};

    if(!font){
        printf("open font failed: %s\n", TTF_GetError());
        return -2;
    }

    while (!quit) {
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT){
                quit = true;
            }else{
                dotHandle(&dot, &e);
            }
        }
        dotMove(&dot, &wallRect);

        renderClearEx(&mRenderer, &backgroundColor);
        SDL_SetRenderDrawColor(mRenderer, 0xff, 0xff, 0xff, 0xFF );
        SDL_RenderDrawRect(mRenderer, &wallRect);
        renderText(&mRenderer, &dot.texture, font, &fontColor, "M o t i o n", WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
        renderImage(&mRenderer, &dotImg, NULL, dot.motion.posX, dot.motion.posY);
        SDL_RenderPresent(mRenderer);
    }

    freeDot(&dot);
    SDL_DestroyWindow(mWin);
    SDL_DestroyRenderer(mRenderer);
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    printf("Quit!\n");

#endif // MOTION
#ifdef ADVANCED_TIMER
    SDL_Window *atWin = NULL;
    SDL_Renderer *atRenderer = NULL;
    SDL_Texture *promtTexture = NULL;
    SDL_Texture *textTexuture = NULL;
    TTF_Font *atFont = NULL;
    SDL_Color atColor = {0,0,0,0xff};

    if(!initWindowAndRenderer(&atWin, &atRenderer)){
        printf("Init window and renderer failed!\n");
        return -1;
    }else{
        TTF_Init();
        atFont = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
        if(!atFont){
            printf("open font failed: %s\n", TTF_GetError());
            return -2;
        }

        bool quit = false;
        SDL_Event e;
        uint32_t totalTick = 0;
        uint32_t lastToltalTick = 0;
        uint32_t startTick = 0;
        uint32_t frameStartTick = SDL_GetTicks();
        uint32_t frameCnt = 0;
        bool timerRunning = false;
        while(!quit){
            while (SDL_PollEvent(&e)) {
                if(e.type == SDL_QUIT){
                    quit = true;
                }else if(e.type == SDL_KEYDOWN){
                    switch (e.key.keysym.sym) {
                    case SDLK_s:
                        if(!timerRunning){
                            startTick = SDL_GetTicks();
                            timerRunning = true;
                        }
                        break;
                    case SDLK_p:
                        if(timerRunning){
                            timerRunning = false;
                            lastToltalTick = totalTick;
                        }
                        break;
                    case SDLK_SPACE:
                        totalTick = 0;
                        lastToltalTick = 0;
                        timerRunning = false;
                        break;
                    }

                }
            }

            if(timerRunning){
                totalTick = SDL_GetTicks() - startTick + lastToltalTick;
            }

            renderClear(&atRenderer);

            renderText(&atRenderer, &promtTexture, atFont, &atColor, "Press s to start timer.", 20, 10);
            renderText(&atRenderer, &promtTexture, atFont, &atColor, "Press p to pause timer.", 20, 40);
            renderText(&atRenderer, &promtTexture, atFont, &atColor, "Press space to reset timer.", 20, 70);

            char *str = malloc(128);
            sprintf(str, "Running %.3f seconds since start", (float)totalTick / 1000.0);
            renderText(&atRenderer, &promtTexture, atFont, &atColor, str, 20, 120);
            free(str);

            str = malloc(128);
            sprintf(str, "FPS = %.3f", (float)frameCnt / ((float)(SDL_GetTicks() - frameStartTick) / 1000.0));
            renderText(&atRenderer, &promtTexture, atFont, &atColor, str, 20, 200);
            free(str);

            SDL_RenderPresent(atRenderer);
            frameCnt++;
        }

        SDL_DestroyWindow(atWin);
        SDL_DestroyRenderer(atRenderer);
        SDL_DestroyTexture(promtTexture);
        SDL_DestroyTexture(textTexuture);
        SDL_Quit();
        TTF_Quit();
        printf("Quit.\n");

    }
#endif // ADVANCED_TIMER
#ifdef TIMING
    SDL_Window *tWin = NULL;
    SDL_Renderer *tRenderer = NULL;
    SDL_Texture *promtTexture = NULL;
    SDL_Texture *textTexuture = NULL;
    SDL_Surface *tSurface = NULL;
    TTF_Font *tFont = NULL;
    SDL_Color tColor = {0,0,0,0xff};
    SDL_Rect promtTextRect = {50, 10, 0, 0};
    SDL_Rect textRect = {20, 100, 0, 0};

    if(!initWindowAndRenderer(&tWin, &tRenderer)){
        printf("Init window and renderer failed!\n");
        return -1;
    }else{
        TTF_Init();
        tFont = TTF_OpenFont(FONT_PATH"cour.ttf", 22);
        if(!tFont){
            printf("open font failed: %s\n", TTF_GetError());
            return -2;
        }

        bool quit = false;
        SDL_Event e;
        Uint32 startTime = 0;


        while(!quit){
            while (SDL_PollEvent(&e)) {
                if(e.type == SDL_QUIT){
                    quit = true;
                }else if(e.type == SDL_KEYDOWN){
                    switch (e.key.keysym.sym) {
                        case SDLK_RETURN:
                            startTime = SDL_GetTicks();
                            printf("restart timer, startTime=%d\n", startTime);
                            break;

                    }
                }
            }
            SDL_SetRenderDrawColor(tRenderer, 0xff, 0xff, 0xff, 0xff);
            SDL_RenderClear(tRenderer);

            tSurface = TTF_RenderText_Solid(tFont, "Press Enter to restart timer.", tColor);
            if(!tSurface){
                printf("TTF render text solid failed: %s\n", TTF_GetError());
                return -3;
            }
            promtTexture = SDL_CreateTextureFromSurface(tRenderer, tSurface);
            if(!promtTexture){
                printf("SDL create texture from surface failed: %s\n", SDL_GetError());
                return  -4;
            }
            promtTextRect.w = tSurface->w;
            promtTextRect.h = tSurface->h;
            SDL_RenderCopy(tRenderer, promtTexture, NULL, &promtTextRect);
            SDL_FreeSurface(tSurface);
            char *str = malloc(128);
            sprintf(str, "Running %d millionsecond since start", SDL_GetTicks() - startTime);
            tSurface = TTF_RenderText_Solid(tFont, str, tColor);
            free(str);
            if(!tSurface){
                printf("TTF render text solid failed: %s\n", TTF_GetError());
                return -3;
            }
            promtTexture = SDL_CreateTextureFromSurface(tRenderer, tSurface);
            if(!promtTexture){
                printf("SDL create texture from surface failed: %s\n", SDL_GetError());
                return  -4;
            }
            textRect.w = tSurface->w;
            textRect.h = tSurface->h;
            SDL_RenderCopy(tRenderer, promtTexture, NULL, &textRect);
            SDL_FreeSurface(tSurface);

            SDL_RenderPresent(tRenderer);
        }

        SDL_DestroyWindow(tWin);
        SDL_DestroyRenderer(tRenderer);
        SDL_DestroyTexture(promtTexture);
        SDL_DestroyTexture(textTexuture);
        SDL_Quit();
        TTF_Quit();
        printf("Quit.\n");
    }


#endif // TIMING
#ifdef SOUND_MUSIC
    SDL_Window *smWin = NULL;
    SDL_Renderer *smRenderer = NULL;
    SDL_Texture *smTexture = NULL;
    Mix_Chunk *smMix1 = NULL;
    Mix_Chunk *smMix2 = NULL;
    Mix_Chunk *smMix3 = NULL;
    Mix_Music *smMixMusic = NULL;

    if(!initWindowAndRenderer(&smWin, &smRenderer)){
        printf("Create window and renderer failed!\n");
        return -1;
    }else{
        smTexture = loadTextureEx(IMAGE_PATH"texture.png", &smRenderer);
        if(!smTexture){
            printf("Load texture error!\n");
            return -2;
        }
        //Initialize SDL_mixer
        if( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 2048 ) < 0 ) {
            printf( "SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError() );
            return -3;
        }
        printf("Mix Open Audio OK!\n");
        smMix1 = Mix_LoadWAV(MIX_PATH"low.wav");
        if(!smMix1){
            printf("load wav error: %s\n", Mix_GetError());
        }
        smMix2 = Mix_LoadWAV(MIX_PATH"medium.wav");
        if(!smMix2){
            printf("load wav error: %s\n", Mix_GetError());
        }
        smMix3 = Mix_LoadWAV(MIX_PATH"high.wav");
        if(!smMix3){
            printf("load wav error: %s\n", Mix_GetError());
        }
        smMixMusic = Mix_LoadMUS(MIX_PATH"beat.wav");
        if(!smMixMusic){
            printf("load wav error: %s\n", Mix_GetError());
        }

        bool quit = false;
        SDL_Event e;
        while(!quit){
            while(SDL_PollEvent(&e)){
                if(e.type == SDL_QUIT){
                    quit = true;
                }else if(e.type == SDL_KEYDOWN){
                    switch (e.key.keysym.sym) {
                        case SDLK_1:
                            Mix_PlayChannel(-1, smMix1, 0);
                            printf("play 1\n");
                            break;
                        case SDLK_2:
                            Mix_PlayChannel(-1, smMix2, 0);
                            printf("play 2\n");
                            break;
                        case SDLK_3:
                            Mix_PlayChannel(-1, smMix3, 0);
                            printf("play 3\n");
                            break;
                        case SDLK_9:
                            if(!Mix_PlayingMusic()){
                                Mix_PlayMusic(smMixMusic, 0);
                            }else{
                                if( Mix_PausedMusic() ){
                                    Mix_ResumeMusic();
                                }
                                else{
                                    Mix_PauseMusic();
                                }
                            }
                            printf("play music\n");
                            break;
                        case SDLK_0:
                            Mix_PauseMusic();
                            printf("pause music\n");
                            break;
                    }
                }
            }

            SDL_SetRenderDrawColor(smRenderer, 0xff, 0xff, 0xff, 0xff);
            SDL_RenderClear(smRenderer);

            SDL_RenderCopy(smRenderer, smTexture, NULL, NULL);
            SDL_RenderPresent(smRenderer);
        }

        SDL_DestroyWindow(smWin);
        SDL_DestroyRenderer(smRenderer);
        SDL_DestroyTexture(smTexture);
        SDL_Quit();
    }

#endif
#ifdef KEY_STATES
    SDL_Window *ksWin = NULL;
    SDL_Renderer *ksRenderer = NULL;
    if(!initWindowAndRenderer(&ksWin, &ksRenderer)){
        printf("Create window and renderer failed!\n");
        return -1;
    }else{

        bool quit = false;
        SDL_Event e;
        while(!quit){
            while (SDL_PollEvent(&e)) {
                if(e.type == SDL_QUIT){
                    quit = true;
                }
            }
            const uint8_t *curKeyStates = SDL_GetKeyboardState(NULL);
            if(curKeyStates[SDL_SCANCODE_UP]){
                printf("up\n");
            }else if(curKeyStates[SDL_SCANCODE_DOWN]){
                printf("down\n");
            }else if(curKeyStates[SDL_SCANCODE_LEFT]){
                printf("left\n");
            }else if(curKeyStates[SDL_SCANCODE_RIGHT]){
                printf("right\n");
            }else if(curKeyStates[SDL_SCANCODE_SPACE]){
                printf("space\n");
            }else {
                printf("release\n");
            }
        }

        SDL_DestroyWindow(ksWin);
        SDL_DestroyRenderer(ksRenderer);
        SDL_Quit();
        printf("quit\n");
    }

#endif // KEY_STATES
#ifdef MOUSE_EVENTS
    SDL_Window *meWin = NULL;
    SDL_Renderer *meRenderer = NULL;
    SDL_Texture *meTexture = NULL;
    SDL_Rect buttonClipRect[3];
    SDL_Rect distRect = {WINDOW_WIDTH/2 - 50, WINDOW_HEIGHT/2 - 50, 100, 100};

    buttonClipRect[0].x = 0;
    buttonClipRect[0].y = 0;
    buttonClipRect[0].w = 100;
    buttonClipRect[0].h = 100;

    buttonClipRect[1].x = 100;
    buttonClipRect[1].y = 0;
    buttonClipRect[1].w = 100;
    buttonClipRect[1].h = 100;

    buttonClipRect[2].x = 200;
    buttonClipRect[2].y = 0;
    buttonClipRect[2].w = 100;
    buttonClipRect[2].h = 100;

    enum MouseState{
        BUTTON_DEFAULT,
        BUTTON_UP,
        BUTTON_PRESSED,
        BUTTON_STATE_TOTAL
    };

    if(!initWindowAndRenderer(&meWin, &meRenderer)){
        printf("Create window and renderer failed!\n");
        return -1;
    }else{
        meTexture = loadTextureEx(IMAGE_PATH"button.png", &meRenderer);
        if(!meTexture){
            printf("Load texture error\n");
            return -2;
        }

        bool quit = false;
        SDL_Event e;
        SDL_Point mousePoint;
        int buttonState = BUTTON_DEFAULT;
        SDL_Rect curButtonState;
        while(!quit){
            while(SDL_PollEvent(&e)){
                if(e.type == SDL_QUIT){
                    quit = true;
                }else{
                    switch (e.type) {
                        case SDL_MOUSEMOTION:
                            mousePoint.x = e.motion.x;
                            mousePoint.y = e.motion.y;
                            buttonState = BUTTON_DEFAULT;
                        break;
                        case SDL_MOUSEBUTTONDOWN:
                            mousePoint.x = e.motion.x;
                            mousePoint.y = e.motion.y;
                            buttonState = BUTTON_PRESSED;
                        break;
                        case SDL_MOUSEBUTTONUP:
                            mousePoint.x = e.motion.x;
                            mousePoint.y = e.motion.y;
                            buttonState = BUTTON_UP;
                        break;
                    }

                    if(mousePoint.x > distRect.x && mousePoint.x < distRect.x + 100
                       && mousePoint.y > distRect.y && mousePoint.y < distRect.y + 100){
                        switch (buttonState) {
                            case BUTTON_PRESSED:
                                curButtonState = buttonClipRect[2];
                            break;
                            case BUTTON_UP:
                                curButtonState = buttonClipRect[1];
                            break;
                            default:
                                curButtonState = buttonClipRect[1];
                            break;
                        }
                    }else{
                        curButtonState = buttonClipRect[0];
                    }
                }
            }
            SDL_SetRenderDrawColor(meRenderer, 0xff, 0xff, 0xff, 0xff);
            SDL_RenderClear(meRenderer);

            SDL_RenderCopy(meRenderer, meTexture, &curButtonState, &distRect);
            SDL_RenderPresent(meRenderer);
        }

        SDL_DestroyWindow(meWin);
        SDL_DestroyRenderer(meRenderer);
        SDL_DestroyTexture(meTexture);
        SDL_Quit();
        printf("Quit!\n");

    }

#endif //MOUSE_EVENTS
#ifdef TURE_TYPE_FONT
    SDL_Window *ttWin = NULL;
    SDL_Renderer *ttRenderer = NULL;
    SDL_Texture *ttTexture = NULL;
    SDL_Surface *ttSurface = NULL;
    TTF_Font *ttFont = NULL;
    SDL_Color ttColor = {0xef, 0, 0, 0xff};
    SDL_Rect distRect;

    if(!initWindowAndRenderer(&ttWin, &ttRenderer)){
        printf("Ctreate window and renderer failed!\n");
        return -1;
    }else{
        /*Notice: Sometimes only test without check pointer */
        TTF_Init();
        ttFont = TTF_OpenFont(FONT_PATH"FZLTCXHJW.TTF", 28);
        if(!ttFont){
            printf("load font error: %s\n", TTF_GetError());
            return -2;
        }
        ttSurface = TTF_RenderText_Solid(ttFont, "Welcome to here!", ttColor);
        ttTexture = SDL_CreateTextureFromSurface(ttRenderer, ttSurface);

        distRect.x = 100;
        distRect.y = 100;
        distRect.w = ttSurface->w;
        distRect.h = ttSurface->h;

        SDL_SetRenderDrawColor(ttRenderer, 0xff, 0xff, 0xff, 0xff);
        SDL_RenderClear(ttRenderer);
        SDL_RenderCopy(ttRenderer, ttTexture, NULL, &distRect);
        SDL_RenderPresent(ttRenderer);

        bool quit = false;
        SDL_Event e;
        while(!quit){
            while(SDL_PollEvent(&e)){
                if(e.type == SDL_QUIT){
                    quit = true;
                }
            }
        }

        SDL_DestroyWindow(ttWin);
        SDL_DestroyRenderer(ttRenderer);
        SDL_DestroyTexture(ttTexture);
        SDL_FreeSurface(ttSurface);
        SDL_Quit();
        TTF_Quit();
        printf("Quit!\n");
    }

#endif // TURE_TYPE_FONT

#ifdef ROTATION_FLIPPING
    SDL_Window *rfWin = NULL;
    SDL_Renderer *rfRenderer = NULL;
    SDL_Texture *rfTexure = NULL;

    if(!initWindowAndRenderer(&rfWin, &rfRenderer)){
        printf("Ctreate window and renderer failed!\n");
        return -1;
    }else{
        rfTexure = loadTextureEx(IMAGE_PATH"rotate.png", &rfRenderer);
        if(!rfTexure){
            printf("Load Texture failed!\n");
            return -2;
        }else{
            double degree = 0;
            SDL_RendererFlip flipType = SDL_FLIP_NONE;
            SDL_Rect rectDist = {100, 100, 100, 100};

            bool quit = false;
            SDL_Event e;
            while(!quit){
                while(SDL_PollEvent(&e) != 0){
                    if(e.type == SDL_QUIT){
                        quit = true;
                    }else if(e.type == SDL_KEYDOWN){
                        switch (e.key.keysym.sym) {
                            case SDLK_UP:
                                degree += 60;
                                printf("degree = %f\n", degree);
                                break;
                            case SDLK_DOWN:
                                degree -= 60;
                                printf("degree = %f\n", degree);
                                break;
                            case SDLK_LEFT:
                                flipType = SDL_FLIP_VERTICAL;
                                printf("SDL_FLIP_VERTICAL\n");
                                break;
                            case SDLK_RIGHT:
                                flipType = SDL_FLIP_HORIZONTAL;
                                printf("SDL_FLIP_HORIZONTAL\n");
                                break;
                            case SDLK_SPACE:
                                flipType = SDL_FLIP_NONE;
                                printf("SDL_FLIP_NONE\n");
                                break;
                        }
                    }
                }
                SDL_SetRenderDrawColor(rfRenderer, 0xff, 0xff, 0xff, 0xff);
                SDL_RenderClear(rfRenderer);

                SDL_RenderCopyEx(rfRenderer, rfTexure, NULL, &rectDist, degree, NULL, flipType);
                SDL_RenderPresent(rfRenderer);

            }
        }

        SDL_DestroyWindow(rfWin);
        SDL_DestroyRenderer(rfRenderer);
        SDL_DestroyTexture(rfTexure);
        SDL_Quit();
        printf("Quit!\n");
    }
#endif
#ifdef ANIMATED_SPRITES
    SDL_Window *asWin = NULL;
    SDL_Renderer *asRenderer = NULL;
    SDL_Texture *asTexture = NULL;
    SDL_Texture *asBackGroundTexture = NULL;
    SDL_Rect rectFrames[FRAMES];
    SDL_Rect rectDist = {100, 100, 100, 200};

    //Set sprite clips
    rectFrames[0].x = 0;
    rectFrames[0].y = 0;
    rectFrames[0].w = 100;
    rectFrames[0].h = 200;

    rectFrames[1].x = 100;
    rectFrames[1].y = 0;
    rectFrames[1].w = 100;
    rectFrames[1].h = 200;

    rectFrames[2].x = 200;
    rectFrames[2].y = 0;
    rectFrames[2].w = 100;
    rectFrames[2].h = 200;

    rectFrames[3].x = 300;
    rectFrames[3].y = 0;
    rectFrames[3].w = 100;
    rectFrames[3].h = 200;

    if(!initWindowAndRenderer(&asWin, &asRenderer)){
        printf("Failed to init!\n");
        return -1;
    }else{
        asTexture = loadTextureEx(IMAGE_PATH"walk.png", &asRenderer);
        asBackGroundTexture = loadTextureEx(IMAGE_PATH"background.png", &asRenderer);
        if(asTexture == NULL || asBackGroundTexture == NULL){
            printf("Failed to load texture!\n");
            return -2;
        }else{
            printf("Init ok!\n");
            SDL_SetTextureBlendMode(asTexture, SDL_BLENDMODE_BLEND);
            SDL_SetTextureBlendMode(asBackGroundTexture, SDL_BLENDMODE_BLEND);

            bool quit = false;
            SDL_Event e;
            uint8_t a = 0xff;
            uint32_t frame = 0;
            while(!quit){
                while(SDL_PollEvent(&e)){
                    if(e.type == SDL_QUIT){
                        quit = true;
                    }else if(e.type == SDL_KEYDOWN){
                        switch (e.key.keysym.sym) {
                            case SDLK_w:
                                a += 32;
                            break;
                            case SDLK_s:
                                a -= 32;
                            break;
                            case SDLK_SPACE:
                                a = 0;
                            break;
                        }
                        printf("alpha = %d\n", a);
                    }
                }
                SDL_SetRenderDrawColor(asRenderer, 0xff, 0xff, 0xff, 0xff);
                SDL_RenderClear(asRenderer);

                SDL_SetTextureAlphaMod(asTexture, a);
                SDL_RenderCopy(asRenderer, asBackGroundTexture, NULL, NULL);

                SDL_RenderCopy(asRenderer, asTexture, &rectFrames[frame / 8], &rectDist);
                SDL_RenderPresent(asRenderer);

                ++frame;
                if(frame / 8 >= FRAMES){
                    frame = 0;
                }
            }
        }
    }
    SDL_DestroyWindow(asWin);
    SDL_DestroyRenderer(asRenderer);
    SDL_DestroyTexture(asTexture);
    SDL_Quit();
    printf("Quit!\n");
#endif

#ifdef ALPHA_BLENDING
    SDL_Window *abWin = NULL;
    SDL_Renderer *abRenderer = NULL;
    SDL_Texture *abTexture = NULL;
    SDL_Texture *abBackGroundTexture = NULL;

    if(!initWindowAndRenderer(&abWin, &abRenderer)){
        printf("Failed to init!\n");
        return -1;
    }else{
        abTexture = loadTextureEx(IMAGE_PATH"round.png", &abRenderer);
        abBackGroundTexture = loadTextureEx(IMAGE_PATH"background.png", &abRenderer);
        if(abTexture == NULL || abBackGroundTexture == NULL){
            printf("Failed to load texture!\n");
            return -2;
        }else{
            printf("Init ok!\n");
            SDL_SetTextureBlendMode(abTexture, SDL_BLENDMODE_BLEND);
            SDL_SetTextureBlendMode(abBackGroundTexture, SDL_BLENDMODE_BLEND);

            bool quit = false;
            SDL_Event e;
            uint8_t a = 0xff;
            while(!quit){
                while(SDL_PollEvent(&e)){
                    if(e.type == SDL_QUIT){
                        quit = true;
                    }else if(e.type == SDL_KEYDOWN){
                        switch (e.key.keysym.sym) {
                            case SDLK_w:
                                a += 32;
                            break;
                            case SDLK_s:
                                a -= 32;
                            break;
                            case SDLK_SPACE:
                                a = 0;
                            break;
                        }
                        printf("alpha = %d\n", a);
                    }
                }
                SDL_SetRenderDrawColor(abRenderer, 0xff, 0xff, 0xff, 0xff);
                SDL_RenderClear(abRenderer);

                SDL_SetTextureAlphaMod(abTexture, a);
                SDL_RenderCopy(abRenderer, abBackGroundTexture, NULL, NULL);
                SDL_RenderCopy(abRenderer, abTexture, NULL, NULL);
                SDL_RenderPresent(abRenderer);
            }
        }
    }
    SDL_DestroyWindow(abWin);
    SDL_DestroyRenderer(abRenderer);
    SDL_DestroyTexture(abTexture);
    SDL_Quit();
    printf("Quit!\n");

#endif // ALPHA_BLENDING

#ifdef COLOR_MODULATION
    SDL_Window *cmWin = NULL;
    SDL_Renderer *cmRenderer = NULL;
    SDL_Texture *cmTexture = NULL;

    if(!initWindowAndRenderer(&cmWin, &cmRenderer)){
        printf("Failed to init!\n");
        return -1;
    }else{
        cmTexture = loadTextureEx(IMAGE_PATH"fourcolor.png", &cmRenderer);

        bool quit = false;
        SDL_Event e;
        uint8_t r = 255;
        uint8_t g = 255;
        uint8_t b = 255;
        while(!quit){
            while(SDL_PollEvent(&e) != 0){
                if(e.type == SDL_QUIT){
                    quit = true;
                }else if(e.type == SDL_KEYDOWN){
                    switch(e.key.keysym.sym){
                        case SDLK_q:
                            r += 32;
                            break;
                        case SDLK_w:
                            g += 32;
                            break;
                        case SDLK_e:
                            b += 32;
                            break;
                        case SDLK_a:
                            r -= 32;
                            break;
                        case SDLK_s:
                            g -= 32;
                            break;
                        case SDLK_d:
                            b -= 32;
                            break;
                    }
                    printf("r=%d, g=%d, b=%d\n", r, g, b);

                }
                SDL_SetRenderDrawColor(cmRenderer, 0xff, 0xff, 0xff, 0xff);
                SDL_RenderClear(cmRenderer);
                SDL_SetTextureColorMod(cmTexture, r, g, b);
                SDL_RenderCopy(cmRenderer, cmTexture, NULL, NULL);
                SDL_RenderPresent(cmRenderer);
            }
        }

        SDL_DestroyWindow(cmWin);
        SDL_DestroyRenderer(cmRenderer);
        SDL_DestroyTexture(cmTexture);
        SDL_Quit();
        printf("Quit!\n");
    }

#endif // COLOR_MODULATION

#ifdef CLIP_RENDER
    SDL_Window *crWin = NULL;
    SDL_Renderer *crRenderer = NULL;
    SDL_Surface *crSurface = NULL;
    SDL_Texture *crTexture = NULL;
    SDL_Rect rectClips[4];
    SDL_Rect rectRender;
    SDL_Surface *crIcon = NULL;

    if(SDL_Init(SDL_INIT_VIDEO) != 0){
        printf("Failed to init SDL: %s\n", SDL_GetError());
        return -1;
    }else{
        if(SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &crWin, &crRenderer) != 0){
            printf("Create window and renderer failed: %s\n", SDL_GetError());
            return -2;
        }else{
            crIcon = IMG_Load("./img/texture.png");
            SDL_SetWindowIcon(crWin, crIcon);
            SDL_FreeSurface(crIcon);
            crIcon = NULL;
            SDL_SetWindowTitle(crWin, "Test Clip Render");
            crSurface = IMG_Load("./img/round.png");

            if(!crSurface){
                printf("load image failed: %s\n", IMG_GetError());
                return -3;
            }else{
                crTexture = SDL_CreateTextureFromSurface(crRenderer, crSurface);
                SDL_FreeSurface(crSurface);
                crSurface = NULL;
                if(!crTexture){
                    printf("Create texture failed: %s\n", SDL_GetError());
                    return -4;
                }else{
                    //clear window
                    SDL_SetRenderDrawColor(crRenderer, 0xff, 0xff, 0xff, 0xff);
                    SDL_RenderClear(crRenderer);

                    bool quit = false;
                    SDL_Event e;
                    while(!quit){
                        while(SDL_PollEvent(&e)){
                            if(e.type == SDL_QUIT){
                                quit = true;
                            }
                        }
                        rectClips[0].x = 0;
                        rectClips[0].y = 0;
                        rectClips[0].w = 100;
                        rectClips[0].h = 100;
                        rectRender.x = 0;
                        rectRender.y = 0;
                        rectRender.w = rectClips[0].w;
                        rectRender.h = rectClips[0].h;
                        SDL_RenderCopy(crRenderer, crTexture, &rectClips[0], &rectRender);

                        rectClips[1].x = 100;
                        rectClips[1].y = 0;
                        rectClips[1].w = 100;
                        rectClips[1].h = 100;
                        rectRender.x = WINDOW_WIDTH - rectClips[1].w;
                        rectRender.y = 0;
                        rectRender.w = rectClips[1].w;
                        rectRender.h = rectClips[1].h;
                        SDL_RenderCopy(crRenderer, crTexture, &rectClips[1], &rectRender);

                        rectClips[2].x = 0;
                        rectClips[2].y = 100;
                        rectClips[2].w = 100;
                        rectClips[2].h = 100;
                        rectRender.x = 0;
                        rectRender.y = WINDOW_HEIGHT - rectClips[2].h;
                        rectRender.w = rectClips[2].w;
                        rectRender.h = rectClips[2].h;
                        SDL_RenderCopy(crRenderer, crTexture, &rectClips[2], &rectRender);

                        rectClips[3].x = 100;
                        rectClips[3].y = 100;
                        rectClips[3].w = 100;
                        rectClips[3].h = 100;
                        rectRender.x = WINDOW_WIDTH - rectClips[3].h;
                        rectRender.y = WINDOW_HEIGHT - rectClips[3].h;
                        rectRender.w = rectClips[3].w;
                        rectRender.h = rectClips[3].h;
                        SDL_RenderCopy(crRenderer, crTexture, &rectClips[3], &rectRender);

                        rectRender.x = WINDOW_WIDTH/2 - 200/2;
                        rectRender.y = WINDOW_HEIGHT/2 - 200/2;
                        rectRender.w = 200;
                        rectRender.h = 200;
                        SDL_RenderCopy(crRenderer, crTexture, NULL, &rectRender);

                        SDL_RenderPresent(crRenderer);
                    }

                }
            }
        }
    }

    SDL_DestroyWindow(crWin);
    SDL_DestroyRenderer(crRenderer);
    IMG_Quit();
    SDL_Quit();


#endif // CLIP_RENDER

#ifdef COLORKEY
    SDL_Window *ckWin = NULL;
    SDL_Renderer *ckRenderer = NULL;
    Texture_t personTexture, backgroundTexture;

    if(SDL_Init(SDL_INIT_VIDEO) != 0){
        printf("Unable to init SDL: %s\n", SDL_GetError());
        return -1;
    }else{
        if(SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &ckWin, &ckRenderer) != 0){
            printf("Create window and renderer failed: %s\n", SDL_GetError());
            return -2;
        }else{
            initTexture(&personTexture, ckRenderer, "./img/person.png");
            initTexture(&backgroundTexture, ckRenderer, "./img/background.png");

            loadFromFile(&personTexture);
            loadFromFile(&backgroundTexture);
            renderTexture(&backgroundTexture, 0, 0);
            renderTexture(&personTexture, 200, 120);
            int x = 200, y = 120;
            bool quit = false;
            SDL_Event e;
            while(!quit){
                while(SDL_PollEvent(&e) != 0){
                    if(e.type == SDL_QUIT){
                        quit = true;
                    }else{
                        if(e.type == SDL_KEYDOWN){
                            switch(e.key.keysym.sym){
                                case SDLK_LEFT:
                                    if(x > 5)
                                        x -= 5;
                                    break;
                                case SDLK_RIGHT:
                                    if(x < WINDOW_WIDTH - personTexture.imgWidth)
                                        x += 5;
                                    break;
                                case SDLK_UP:
                                    if(y > 5)
                                        y -= 5;
                                    break;
                                case SDLK_DOWN:
                                    if(y < WINDOW_HEIGHT - personTexture.imgHeight)
                                        y += 5;
                                    break;
                            }
                            renderTexture(&backgroundTexture, 0, 0);
                            renderTexture(&personTexture, x, y);
                            SDL_RenderPresent(ckRenderer);
                        }

                    }
                }
                SDL_RenderPresent(ckRenderer);
            }
        }
    }

    freeTexture(&personTexture);
    freeTexture(&backgroundTexture);
    SDL_DestroyWindow(ckWin);
    SDL_DestroyRenderer(ckRenderer);
    IMG_Quit();
    SDL_Quit();

#endif // COLORKEY

#ifdef VIEWPORT
    SDL_Window *vpWin = NULL;
    SDL_Texture *vpTexture = NULL;
    SDL_Renderer *vpRenderer = NULL;
    SDL_Surface *vpSurface = NULL;

    if(SDL_Init(SDL_INIT_VIDEO) != 0){
        printf("Unable to init SDL: %s\n", SDL_GetError());
        return -1;
    }else{
        if(SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &vpWin, &vpRenderer) != 0){
            printf("Unable to create window and renderer: %s\n", SDL_GetError());
            return -1;
        }else{
            vpSurface = IMG_Load("./img/texture.png");
            vpTexture = SDL_CreateTextureFromSurface(vpRenderer, vpSurface);
            SDL_FreeSurface(vpSurface);

            SDL_SetRenderDrawColor(vpRenderer, 255, 165, 0, 0xff);
            SDL_RenderClear(vpRenderer);

            SDL_Rect topLeftRect = {0, 0, WINDOW_WIDTH/2, WINDOW_HEIGHT/2};
            SDL_RenderSetViewport(vpRenderer, &topLeftRect);
            SDL_RenderCopy(vpRenderer, vpTexture, NULL, NULL);

            SDL_Rect topRigntRect = {WINDOW_WIDTH/2, 0, WINDOW_WIDTH/2, WINDOW_HEIGHT/2};
            SDL_RenderSetViewport(vpRenderer, &topRigntRect);
            SDL_RenderCopy(vpRenderer, vpTexture, NULL, NULL);

            SDL_Rect bottomRect = {0, WINDOW_HEIGHT/2, WINDOW_WIDTH, WINDOW_HEIGHT/2};
            SDL_RenderSetViewport(vpRenderer, &bottomRect);
            SDL_RenderCopy(vpRenderer, vpTexture, NULL, NULL);

            SDL_RenderPresent(vpRenderer);
            SDL_Delay(5000);
        }
    }

    SDL_Quit();

#endif // VIEWPORT

#ifdef GEOMETRY_RENDER
    SDL_Window *geoWin = NULL;
    SDL_Renderer *geoRenderer = NULL;

    if(SDL_Init(SDL_INIT_VIDEO) != 0){
        printf("Unable to init SDL: %s\n", SDL_GetError());
        return -1;
    }else{
        if(SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &geoWin, &geoRenderer)){
            printf("Unable to create window and renderer: %s\n", SDL_GetError());
            return -1;
        }else{
            //clear window with drawing color
            SDL_SetRenderDrawColor(geoRenderer, 0xff, 0xff, 0xff, 0xff);
            SDL_RenderClear(geoRenderer);
            //draw rectangle
            SDL_Rect fillRect = {WINDOW_WIDTH/4, WINDOW_HEIGHT/4, WINDOW_WIDTH/2, WINDOW_HEIGHT/2};
            SDL_SetRenderDrawColor(geoRenderer, 0, 0, 0xff, 0xff);
            SDL_RenderFillRect(geoRenderer, &fillRect);
            //draw outline rectangle
            SDL_Rect outlineRect = {WINDOW_WIDTH/8, WINDOW_HEIGHT/8, WINDOW_WIDTH*3/4, WINDOW_HEIGHT*3/4};
            SDL_SetRenderDrawColor(geoRenderer, 0xff, 0, 0, 0xff);
            SDL_RenderDrawRect(geoRenderer, &outlineRect);
            //draw line
            SDL_SetRenderDrawColor(geoRenderer, 0, 0xff, 0, 0xff);
            SDL_RenderDrawLine(geoRenderer, 0, WINDOW_HEIGHT/2, WINDOW_WIDTH, WINDOW_HEIGHT/2);
            //draw point
            SDL_SetRenderDrawColor(geoRenderer, 0xff, 0, 0xff, 0xff);
            for(int i = 0; i < WINDOW_HEIGHT; i += 5){
                SDL_RenderDrawPoint(geoRenderer, WINDOW_WIDTH/2, i);
            }

            SDL_RenderPresent(geoRenderer);
            SDL_Delay(3000);
        }
    }

    SDL_DestroyWindow(geoWin);
    SDL_DestroyRenderer(geoRenderer);
    SDL_Quit();

#endif // GEOMETRY_RENDER


#ifdef KEYPRESS

    if(false == init()){
        printf("Failed to init!\n");
        return -1;
    }else{
        if(false == loadMedia()){
            printf("Failed to load media!\n");
            return -1;
        }else{
            bool quit = false;
            SDL_Event e;
            gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_DEFAULT];
            while(!quit){
                while(SDL_PollEvent(&e) != 0){
                    if(SDL_QUIT == e.type){
                        quit = true;
                    }else if(SDL_KEYDOWN == e.type){
                        //printf("key code = %d\n", e.key.keysym.sym);
                        switch(e.key.keysym.sym){
                            case SDLK_UP:
                                printf("press up\n");
                                gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_UP];
                                break;

                            case SDLK_DOWN:
                                printf("press down\n");
                                gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_DOWN];
                                break;

                            case SDLK_LEFT:
                                printf("press left\n");
                                gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_LEFT];
                                break;

                            case SDLK_RIGHT:
                                printf("press right\n");
                                gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_RIGHT];
                                break;

                            case SDLK_SPACE:
                                printf("press space\n");
                                gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_SPACE];
                                break;

                            case SDLK_RETURN:
                                printf("press enter\n");
                                gCurSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_ENTER];
                                break;
                        }
                    }
                }

                SDL_BlitScaled(gCurSurface, NULL, gWinSurface, &gWinRect);
                SDL_UpdateWindowSurface(gWin);
            }
        }
    }

    freeMedia();

#endif // KEYPRESS

#ifdef TEXTURE

    // image=>surface=>texture=>renderer
    if(false == init2()){
        printf("Failed to init2!\n");
        return -1;
    }else{
        gTexture = loadTexture("./img/texture.png");
        if(!gTexture){
            printf("Load texture failed: %s\n", SDL_GetError());
            return -1;
        }else{
            SDL_RenderClear(gRender);
            SDL_RenderCopy(gRender, gTexture, NULL, NULL);
            SDL_RenderPresent(gRender);
            SDL_Delay(3000);
        }
    }

#endif // TEXTURE

    return 0;
}
